#include "DigitalSignageManager.h"
#include "Protocol/ProtocolApi.h"
#include "StreamerCurtainPlay.h"
#include "log.h"
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include "Network/Socket.h"
#include "PictureFileStream.h"
#include "FileTransfer.h"
#include "BgmCurtainPlay.h"
#include <sys/stat.h>
#include "ZipUtil.h"
#include "ScreenMirrorStream.h"
#include "errorCode.h"


extern "C"
{
	#include "md5.h"
}


using namespace Protocol;




DigitalSignageManager::Ptr DigitalSignageManager::Instance(){
    static auto ptr = std::make_shared<DigitalSignageManager>();
    return ptr;
}


DigitalSignageManager::DigitalSignageManager(){
    RegistRPC();
}

DigitalSignageManager::~DigitalSignageManager(){

}

void DigitalSignageManager::RegistRPC(){
    IProtocolInterface::GetInstance()->AuditoryworksRegistRequestRpcEx("CloudUploadStream", 
        [this](const Json::Value& req_params, Json::Value& res_result, std::string& errinfo, int& errorCode){
            return CloudUploadStream(req_params, res_result, errinfo, errorCode);
        });
}


bool DigitalSignageManager::CloudUploadStream(const Json::Value& req_params, Json::Value& res_result, 
    std::string& errinfo, int& errorCode){
    if(!req_params.isMember("filename") || !req_params.isMember("md5") || !req_params.isMember("type") || !req_params.isMember("url")){
        errorf("req_params error\n");
        return false;
    }

    std::string type = req_params["type"].asString();
    if(type == "Streamer"){
        return DigitalSignage(req_params, res_result, errinfo, errorCode);
    }

    if(type == "bgm"){
        return bgmPlay(req_params, res_result, errinfo);
    }


    return false;
}

bool DigitalSignageManager::bgmPlay(const Json::Value& req_params, Json::Value& res_result, std::string& errinfo){

    Media::BgmCurtainPlay::instance()->stopBgmCurtain();
    
    if(!processDownFile(req_params["url"].asString(), req_params["md5"].asString(), BGM_ROOT_DIR, req_params["filename"].asString())){
        return false;
    }
    std::string path;
    DiskController::instance()->getRealTimeRootPath(path);
    return Media::BgmCurtainPlay::instance()->playBgmCurtain(path);
}



bool DigitalSignageManager::processDownFile(std::string url, std::string resmd5,std::string subPath, std::string filename){
    if(!DiskController::instance()->setRealTimeRootPath()){
		LOG_PrintError("faild get root path\n");
		return false;
	}
    DiskController::instance()->clearStreamerFiles(subPath);
    //1 download upgrade file
    bool done_ret = false;
    auto resultCb = [&done_ret](const Fdt::SockException &ex){
        if (ex) {
            WarnL << "network err:" << ex.getErrCode() << " " << ex.what();
        } else {
            WarnL << "succeed"  << ex.what();
        }
        done_ret = true;
    };

    int down_progress = 0;
    int cur_progress = -1;
    unsigned long long time_out = 0;
    std::string path;
    DiskController::instance()->getRealTimeBusinessPath(subPath, path);
    std::string filePath = path + "/" + filename;

    std::string flashpath;
    DiskController::instance()->getRealTimeRootPath(flashpath);

    if(!DiskController::instance()->isMountPath(flashpath)){
        LOG_PrintError("flashpath flash is not mount %s\n", flashpath.c_str());
        return false;
    }
    
    std::function<void (void)> stop_func;
    IProtocolInterface::GetInstance()->HttpDownloadFile(url, filePath, resultCb, down_progress, stop_func);
    while(!done_ret){        
        if(cur_progress != down_progress){
            
            cur_progress = down_progress;
            time_out = vdo_get_time();
        }else{
            if(time_out != 0){
                if(vdo_get_time() - time_out > 5000){
                    stop_func();
                    break;
                }
            }
        }
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    if(down_progress != 100){
        errorf("down cloud file faild\n");
        return false;
    }

	std::string md5 = strHex2Val(resmd5.c_str(), resmd5.size());
    if(!compareMd5(filePath, md5.c_str())){
        errorf("compareMd5 Md5 faild, file failure\n");
        return false;
    }
    
    ZipUtil zip;
    if(zip.unZipFile(filePath, path) != 0){
        errorf("unzip cloud file faild\n");
        return false;
    }
    return true;
}


bool DigitalSignageManager::DigitalSignage(const Json::Value& req_params, Json::Value& res_result, 
    std::string& errinfo, int& errorCode){

    ///判定设备当前是否在投屏
    if(Media::ScreenMirrorStream::instance()->getShareScreenStatus())
    {
        errinfo = "The device is displaying screen mirroring information, please try again later.";
        errorCode = Media::ScreenPlaying;
        LOG_PrintError("DigitalSignage faild, errinfo=%s\n", errinfo.c_str());
		return false;        
    }

    Media::StreamerCurtainPlay::instance()->stopStreamerCurtain();//先停止播放

    if(!processDownFile(req_params["url"].asString(), req_params["md5"].asString(), STREAM_ROOT_DIR, req_params["filename"].asString())){
        return false;
    }
    std::string path;
    DiskController::instance()->getRealTimeRootPath(path);
    if(!Media::StreamerCurtainPlay::instance()->playStreamerCurtain(Media::WEB_STREAMER, path)){
        errorf("play streamer curtain faild\n");
        return false;
    }

    return true;
}


bool DigitalSignageManager::compareMd5(std::string filename, const char *md5){
    bool ret = false;
	unsigned int size;
	unsigned char *pData;
	unsigned char outputTemp[16] = {0};
	const char *md = md5;
	
	
	int fd = open(filename.c_str(),O_RDWR);
	if (fd < 0)
	{
		printf("open %d failed!\n", fd);
		return false;
	}
	size = lseek(fd, 0, SEEK_END);

	pData = (unsigned char *)mmap(NULL,
								  size,
								  PROT_READ,
								  MAP_PRIVATE,
								  fd,
								  0);
	md5_calc(outputTemp, pData, size);

	printf("md5 ------------------------ %s\n", md);
	uint8_t *mddd = (uint8_t *)md;
	printf("local md--->%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X \n", mddd[0],mddd[1], mddd[2], mddd[3], mddd[4],
				mddd[5], mddd[6], mddd[7], mddd[8], mddd[9], mddd[10], mddd[11], mddd[12], mddd[13], mddd[14], mddd[15]);
	printf("local md--->%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X \n", outputTemp[0],outputTemp[1], outputTemp[2], outputTemp[3], outputTemp[4],
				outputTemp[5], outputTemp[6], outputTemp[7], outputTemp[8], outputTemp[9], outputTemp[10], outputTemp[11], outputTemp[12], outputTemp[13], outputTemp[14], outputTemp[15]);

	if (memcmp(outputTemp, md5, 16) == 0)
	{
		LOG_PrintInfo("Download succeed.\n");
        ret = true;
	}

	munmap((void *)pData, size);
    close(fd);
	return ret;
}



